# IMPORT

# ARGS

# MAIN
oo::class create CodePad {
    variable Width Height PadWidget ActionCollection MultiYScroll Language

    constructor {p lang {plugins {}} {w {}} {h {}}} {
        set Width $w
        set Height $h
        set PadWidget $p
        # wm withdraw .
        text $PadWidget -bd 0 -wrap none \
            -undo 1 -insertofftime 0 -maxundo 0
        # reset background color of tag sel
        $PadWidget tag configure sel -background #0B0B0B
        $PadWidget tag configure search -background #CCCCFF
        my redirectPadAction

        set Language [$lang new _$PadWidget]
        set MultiYScroll [MultiYScroll new $PadWidget]

        set ActionCollection [ActionCollection new [PluginFactory new $Language [self object]] $plugins]

        if {$Width != {}} {$PadWidget configure -width $Width}
        if {$Height != {}} {$PadWidget configure -height $Height}
        pack $PadWidget -side right -fill both -expand 1
        # my centerWindow
    }

    method centerWindow {} {
        update
        set screenWidth [winfo screenwidth .]
        set screenHeight [winfo screenheight .]
        set padWidth [winfo reqwidth $PadWidget]
        set padHeight [winfo reqheight $PadWidget]

        wm geometry . +[expr ($screenWidth-$padWidth)/2]+[expr ($screenHeight-$padHeight)/2]
        wm deiconify .
    }

    method redirectPadAction {} {
        uplevel #0 \
            rename $PadWidget _$PadWidget ;\
            proc ::$PadWidget {args} [subst {
                [self object] filterAction {*}\$args
                uplevel #0 _$PadWidget \$args
            }]
    }

    method filterAction {args} {
        set actionType [lindex $args 0]
        set rest [lreplace $args 0 0]
        foreach f [info object methods $ActionCollection -all] {
            if {$actionType == $f} {
                $ActionCollection $actionType {*}$rest
            }
        }
    }

    destructor {
        $MultiYScroll destroy
        $ActionCollection destroy
        destroy $PadWidget
    }
}

proc ::oo::Helpers::runAfterIdle {script} {
    eval [list after idle $script]
}

proc ::oo::Helpers::do {code while cond} {
    uplevel 1 $code
    tailcall $while $cond $code
}

proc ::do {code while cond} {
    uplevel 1 $code
    tailcall $while $cond $code
}